
#pragma once
#include "UserInput.hpp"
#include <memory>
#include <string>

struct GLFWwindow;

namespace Data {

class Window {
public:
  struct Des {
    std::string title = "Window Sample";
    uint32_t width = 1920;
    uint32_t height = 1080;
    bool isFullScreen = false;
    bool isResizable = true;
  };

  ~Window();

  class ICallbacks {
  public:
    virtual void windowFocused() = 0;
    virtual void keyboardEvent(const KeyboardEvent &event) = 0;
    virtual void mouseEvent(const MouseEvent &event) = 0;
    virtual void windowSizeChanged(int w, int h) = 0;
    virtual void renderStart() = 0;
    virtual void render() = 0;
    virtual void renderEnd() = 0;
    virtual void setup() = 0;
    virtual ~ICallbacks() {}
  };

  /*
   * Create Windows
   */
  static std::shared_ptr<Window> createWindow(ICallbacks *callbacks,
                                              const Des &description);
  void setWindowTitle(const std::string &title);
  void setWindowSize(uint32_t width, uint32_t height);
  void setFullScreen(bool mode);
  void setResizable(bool mode);
  void pullEvents();
  const Des &getWindowDescription() const { return m_description; }
  void renderLoop();

  /*
   */
  void shutdown();

protected:
  Window(ICallbacks *callbacks, const Des &description);

private:
  friend class ImpCallbacks;

  void checkWindowSize();
  const glm::vec2 &getMouseScale() const { return m_mouseScale; }

  glm::vec2 m_mouseScale;
  bool m_isDebug;
  ICallbacks *mp_callbacks = nullptr;
  GLFWwindow *mp_window = nullptr;
  Des m_description;
};
} // namespace Data
